/**
 * 工具函数库
 * @author Wu.Liang
 * @description 通用工具函数，包括格式化、验证、计算等
 */

import dayjs from 'dayjs'
import CryptoJS from 'crypto-js'
import { STATUS } from '@/constants/enums'

// Token存储key
const TOKEN_KEY = 'access_token'
const REFRESH_TOKEN_KEY = 'refresh_token'

/**
 * 设置Token到本地存储
 */
export const setToken = (token: string): void => {
    localStorage.setItem(TOKEN_KEY, token)
}

/**
 * 获取本地存储的Token
 */
export const getToken = (): string => {
    return localStorage.getItem(TOKEN_KEY) || ''
}

/**
 * 移除本地存储的Token
 */
export const removeToken = (): void => {
    localStorage.removeItem(TOKEN_KEY)
    localStorage.removeItem(REFRESH_TOKEN_KEY)
}

/**
 * 设置刷新Token
 */
export const setRefreshToken = (refreshToken: string): void => {
    localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken)
}

/**
 * 获取刷新Token
 */
export const getRefreshToken = (): string => {
    return localStorage.getItem(REFRESH_TOKEN_KEY) || ''
}

/**
 * 格式化日期时间
 */
export function formatDate(date: string | number | Date, format: string = 'YYYY-MM-DD HH:mm:ss'): string {
    if (!date) return ''
    return dayjs(date).format(format)
}

/**
 * 格式化日期时间（增强版）
 */
export const formatDateTime = (
    date: Date | string | number,
    format = 'YYYY-MM-DD HH:mm:ss'
): string => {
    const d = new Date(date)
    if (isNaN(d.getTime())) return ''

    const year = d.getFullYear()
    const month = String(d.getMonth() + 1).padStart(2, '0')
    const day = String(d.getDate()).padStart(2, '0')
    const hours = String(d.getHours()).padStart(2, '0')
    const minutes = String(d.getMinutes()).padStart(2, '0')
    const seconds = String(d.getSeconds()).padStart(2, '0')

    return format
        .replace('YYYY', year.toString())
        .replace('MM', month)
        .replace('DD', day)
        .replace('HH', hours)
        .replace('mm', minutes)
        .replace('ss', seconds)
}

/**
 * 格式化相对时间
 */
export const formatRelativeTime = (date: Date | string | number): string => {
    const now = new Date()
    const target = new Date(date)
    const diff = now.getTime() - target.getTime()

    const minute = 60 * 1000
    const hour = 60 * minute
    const day = 24 * hour
    const week = 7 * day
    const month = 30 * day
    const year = 365 * day

    if (diff < minute) return '刚刚'
    if (diff < hour) return `${Math.floor(diff / minute)}分钟前`
    if (diff < day) return `${Math.floor(diff / hour)}小时前`
    if (diff < week) return `${Math.floor(diff / day)}天前`
    if (diff < month) return `${Math.floor(diff / week)}周前`
    if (diff < year) return `${Math.floor(diff / month)}个月前`
    return `${Math.floor(diff / year)}年前`
}

/**
 * 获取当前时间戳
 */
export function getTimestamp(): number {
    return Date.now()
}

/**
 * 防抖函数
 */
export function debounce<T extends(...args: any[]) => void>(
    func: T,
    wait: number
): (...args: Parameters<T>) => void {
    let timeout: ReturnType<typeof setTimeout>
    return function executedFunction(...args: Parameters<T>) {
        const later = () => {
            clearTimeout(timeout)
            func(...args)
        }
        clearTimeout(timeout)
        timeout = setTimeout(later, wait)
    }
}

/**
 * 节流函数
 */
export function throttle<T extends(...args: any[]) => void>(
    func: T,
    limit: number
): (...args: Parameters<T>) => void {
    let inThrottle: boolean
    return function executedFunction(...args: Parameters<T>) {
        if (!inThrottle) {
            func(...args)
            inThrottle = true
            setTimeout(() => inThrottle = false, limit)
        }
    }
}

/**
 * 深拷贝
 */
export function deepClone<T>(obj: T): T {
    if (obj === null || typeof obj !== 'object') return obj
    if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T
    if (obj instanceof Array) return obj.map(item => deepClone(item)) as unknown as T
    if (typeof obj === 'object') {
        const copy = {} as { [key: string]: any }
        Object.keys(obj).forEach(key => {
            copy[key] = deepClone((obj as { [key: string]: any })[key])
        })
        return copy as T
    }
    return obj
}

/**
 * 生成UUID
 */
export function generateUUID(): string {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        const r = Math.random() * 16 | 0
        const v = c === 'x' ? r : (r & 0x3 | 0x8)
        return v.toString(16)
    })
}

/**
 * 生成随机字符串
 */
export const generateRandomString = (length = 8): string => {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    let result = ''
    for (let i = 0; i < length; i++) {
        result += chars.charAt(Math.floor(Math.random() * chars.length))
    }
    return result
}

/**
 * 获取文件扩展名
 */
export function getFileExtension(filename: string): string {
    return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2)
}

/**
 * 格式化文件大小
 */
export function formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 Bytes'
    const k = 1024
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))
    return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))  } ${  sizes[i]}`
}

/**
 * 格式化金额
 */
export function formatMoney(amount: number | string, precision: number = 2): string {
    if (amount === null || amount === undefined || amount === '') return '0.00'
    const num = typeof amount === 'string' ? parseFloat(amount) : amount
    if (isNaN(num)) return '0.00'
    return num.toFixed(precision).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}

/**
 * 验证手机号
 */
export function isValidPhone(phone: string): boolean {
    return /^1[3-9]\d{9}$/.test(phone)
}

/**
 * 验证邮箱
 */
export function isValidEmail(email: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}

/**
 * 验证身份证号
 */
export function isValidIdCard(idCard: string): boolean {
    return /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(idCard)
}

/**
 * 验证密码强度
 */
export function isValidPassword(password: string): boolean {
    return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/.test(password)
}

/**
 * 验证密码强度详细
 */
export const validatePasswordStrength = (password: string): {
    strength: 'weak' | 'medium' | 'strong'
    score: number
    suggestions: string[]
} => {
    let score = 0
    const suggestions: string[] = []

    if (password.length < 8) {
        suggestions.push('密码长度至少8位')
    } else {
        score += 1
    }

    if (!/[a-z]/.test(password)) {
        suggestions.push('包含小写字母')
    } else {
        score += 1
    }

    if (!/[A-Z]/.test(password)) {
        suggestions.push('包含大写字母')
    } else {
        score += 1
    }

    if (!/\d/.test(password)) {
        suggestions.push('包含数字')
    } else {
        score += 1
    }

    if (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) {
        suggestions.push('包含特殊字符')
    } else {
        score += 1
    }

    let strength: 'weak' | 'medium' | 'strong' = 'weak'
    if (score >= 4) strength = 'strong'
    else if (score >= 2) strength = 'medium'

    return { strength, score, suggestions }
}

/**
 * 加密字符串
 */
export function encrypt(text: string, key: string = 'smart-community'): string {
    return CryptoJS.AES.encrypt(text, key).toString()
}

/**
 * 解密字符串
 */
export function decrypt(cipherText: string, key: string = 'smart-community'): string {
    const bytes = CryptoJS.AES.decrypt(cipherText, key)
    return bytes.toString(CryptoJS.enc.Utf8)
}

/**
 * 获取URL参数
 */
export function getUrlParam(name: string): string | null {
    const url = new URL(window.location.href)
    return url.searchParams.get(name)
}

/**
 * 下载文件
 */
export function downloadFile(url: string, filename?: string): void {
    const link = document.createElement('a')
    link.href = url
    if (filename) {
        link.download = filename
    }
    link.target = '_blank'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
}

/**
 * 复制文本到剪贴板
 */
export async function copyToClipboard(text: string): Promise<boolean> {
    try {
        if (navigator.clipboard) {
            await navigator.clipboard.writeText(text)
            return true
        } else {
            // 兼容旧版浏览器
            const textArea = document.createElement('textarea')
            textArea.value = text
            document.body.appendChild(textArea)
            textArea.select()
            document.execCommand('copy')
            document.body.removeChild(textArea)
            return true
        }
    } catch (error) {
        console.error('复制到剪贴板失败:', error)
        return false
    }
}

/**
 * 获取随机颜色
 */
export function getRandomColor(): string {
    return `#${  Math.floor(Math.random() * 16777215).toString(16)}`
}

/**
 * 树形数据扁平化
 */
export function flattenTree<T extends Record<string, any>>(
    data: T[],
    childrenKey: string = 'children'
): T[] {
    const result: T[] = []
    function traverse(nodes: T[]) {
        nodes.forEach(node => {
            result.push(node)
            if (node[childrenKey] && Array.isArray(node[childrenKey])) {
                traverse(node[childrenKey])
            }
        })
    }
    traverse(data)
    return result
}

/**
 * 数组转树形结构
 */
export function arrayToTree<T extends Record<string, any>>(
    data: T[],
    idKey: string = 'id',
    parentIdKey: string = 'parentId',
    childrenKey: string = 'children'
): T[] {
    const map = new Map<any, T>()
    const roots: T[] = []

    // 创建映射
    data.forEach(item => {
        map.set(item[idKey], { ...item, [childrenKey]: [] })
    })

    // 构建树形结构
    data.forEach(item => {
        const node = map.get(item[idKey])!
        const parentId = item[parentIdKey]

        if (parentId === null || parentId === undefined || parentId === 0 || parentId === '0') {
            roots.push(node)
        } else {
            const parent = map.get(parentId)
            if (parent) {
                parent[childrenKey].push(node)
            } else {
                roots.push(node)
            }
        }
    })

    return roots
}

/**
 * 获取对象属性值（支持嵌套路径）
 */
export const getObjectValue = (obj: any, path: string, defaultValue?: any): any => {
    const keys = path.split('.')
    let result = obj

    for (const key of keys) {
        if (result === null || result === undefined) {
            return defaultValue
        }
        result = result[key]
    }

    return result !== undefined ? result : defaultValue
}

/**
 * 设置对象属性值（支持嵌套路径）
 */
export const setObjectValue = (obj: any, path: string, value: any): void => {
    const keys = path.split('.')
    const lastKey = keys.pop()!
    let target = obj

    for (const key of keys) {
        if (!(key in target) || typeof target[key] !== 'object') {
            target[key] = {}
        }
        target = target[key]
    }

    target[lastKey] = value
}

/**
 * 获取浏览器信息
 */
export const getBrowserInfo = () => {
    const ua = navigator.userAgent
    const isChrome = /Chrome/.test(ua) && /Google Inc/.test(navigator.vendor)
    const isFirefox = /Firefox/.test(ua)
    const isSafari = /Safari/.test(ua) && /Apple Computer/.test(navigator.vendor)
    const isEdge = /Edge/.test(ua)
    const isIE = /Trident/.test(ua)

    return {
        isChrome,
        isFirefox,
        isSafari,
        isEdge,
        isIE,
        isMobile: /Mobile/.test(ua),
        isTablet: /Tablet/.test(ua)
    }
}

/**
 * 滚动到指定元素
 */
export const scrollToElement = (element: Element | string, offset = 0): void => {
    const target = typeof element === 'string' ? document.querySelector(element) : element
    if (target) {
        const targetPosition = target.getBoundingClientRect().top + window.pageYOffset - offset
        window.scrollTo({
            top: targetPosition,
            behavior: 'smooth'
        })
    }
}

/**
 * 检查是否为图片文件
 */
export const isImageFile = (fileName: string): boolean => {
    const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
    const extension = getFileExtension(fileName).toLowerCase()
    return imageExtensions.includes(extension)
}

/**
 * 压缩图片
 */
export const compressImage = (
    file: File,
    quality = 0.8,
    maxWidth = 1920,
    maxHeight = 1080
): Promise<File> => {
    return new Promise((resolve) => {
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')!
        const img = new Image()

        img.onload = () => {
            // 计算压缩后的尺寸
            let { width, height } = img
            if (width > maxWidth) {
                height = (height * maxWidth) / width
                width = maxWidth
            }
            if (height > maxHeight) {
                width = (width * maxHeight) / height
                height = maxHeight
            }

            canvas.width = width
            canvas.height = height

            // 绘制并压缩
            ctx.drawImage(img, 0, 0, width, height)
            canvas.toBlob(
                (blob) => {
                    const compressedFile = new File([blob!], file.name, {
                        type: file.type,
                        lastModified: Date.now()
                    })
                    resolve(compressedFile)
                },
                file.type,
                quality
            )
        }

        img.src = URL.createObjectURL(file)
    })
}

// 检查状态是否为启用
export function isEnabled(status: number): boolean {
    return status === STATUS.ENABLED
}

// 检查状态是否为禁用
export function isDisabled(status: number): boolean {
    return status === STATUS.DISABLED
}
